package org.ehe.business.bom.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.business.bom.domain.BomMaster;
import org.ehe.business.bom.domain.BomStructureTemp;
import org.ehe.business.bom.domain.bo.BomPageBo;
import org.ehe.business.bom.domain.bo.BomStructureTempBo;
import org.ehe.business.bom.domain.dto.*;
import org.ehe.business.bom.domain.vo.BomPageVO;
import org.ehe.business.bom.domain.vo.BomStructureTempVo;
import org.ehe.business.bom.service.BomBusinessService;
import org.ehe.business.bom.service.BomExcelImportService;
import org.ehe.business.bom.service.BomStructureTempService;
import org.ehe.business.monitor.MonitorMethod;
import org.ehe.business.overdue.extract.BomDataExtractor;
import org.ehe.business.overdue.extract.BomDataExtractor;
import org.ehe.common.core.BaseController;
import org.ehe.common.core.constant.StatusEnum;
import org.ehe.common.core.domain.R;
import org.ehe.common.core.exception.BusinessException;
import org.ehe.common.core.exception.ServiceException;
import org.ehe.common.log.annotation.Log;
import org.ehe.common.log.enums.BusinessType;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.erp.enums.ErpAuditStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * BOM业务流程控制器
 * @author :zhangnn
 * @className :BomBusinessController
 * @description: BOM完整业务流程管理：设计BOM创建、BOM转换、变更管理、MRP生成等
 * @date 2025-07-30 15:08:23
 */

@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/bom")
public class BomBusinessController extends BaseController {
    private final BomBusinessService bomBusinessService;

    /**
     * 分页请求
     * @param bo
     * @param pageQuery
     * @return
     */
    @GetMapping("/page")
    public TableDataInfo<BomPageVO> pageBoms(BomPageBo bo, PageQuery pageQuery) {
        log.info("BOM分页查询请求: bomCode={}, projectId={}", bo.getBomCode(), bo.getProjectId());

        try {
            return bomBusinessService.pageBoms(bo, pageQuery);
        } catch (Exception e) {
            log.error("BOM分页查询失败", e);
            throw new ServiceException("BOM分页查询失败: " + e.getMessage());
        }
    }

    /**
     * 详情
     * @param bo
     * @param pageQuery
     * @return
     */
    @SaCheckPermission("bom:view:index")
    @GetMapping("/detail/{id}")
    public R<BomPageVO> detail(BomPageBo bo, PageQuery pageQuery) {
        try {
            bo.setId(bo.getId());
            pageQuery.setPageNum(1);
            pageQuery.setPageSize(10);
            return R.ok("获取详情成功！",bomBusinessService.detail(bo, pageQuery));
        } catch (Exception e) {
            log.error("BOM分页查询失败", e);
            throw new ServiceException("BOM分页查询失败: " + e.getMessage());
        }
    }

    /**
     * 创建设计BOM (EBOM)
     * @param request
     * @description 项目启动阶段创建设计BOM（EBOM）
     * @return
     */
    @SaCheckPermission("bom:creation:index")
    @MonitorMethod(bizType = "bomOverdue", extractor = BomDataExtractor.class)
    @PostMapping("/create-design-bom")
    @Log(title = "创建设计BOM", businessType = BusinessType.INSERT, nameField = "bomName")
    public R<BomCreationResult> createDesignBom(@Valid @RequestBody BomCreationRequest request) {
        boolean isUpdate = request.getId() != null;
        String operation = isUpdate ? "更新" : "创建";
        if(isUpdate){
            if(ErpAuditStatus.ALLOW_EDIT.contains(request.getStatus())){
                throw new BusinessException("草稿状态下才可以修改");
            }
        }
        log.info("{}设计BOM请求: projectId={}, projectName={}, bomId={}",
            operation, request.getProjectId(), request.getProjectName(), request.getId());

        try {
            BomCreationResult result = bomBusinessService.saveOrUpdateDesignBom(request);
            if (Objects.nonNull(request)) {
                return R.ok("设计BOM创建成功");
            } else {
                return R.fail(result.getMessage());
            }
        } catch (Exception e) {
            log.error("创建设计BOM失败", e);
            return R.fail("创建设计BOM失败: " + e.getMessage());
        }
    }

    /**
     * 提交EBOM审批
     * @param bomId
     * @param workflowInstanceId 工作流实例ID
     * @return
     */
    @SaCheckPermission("bom:creation:submit")
    @MonitorMethod(bizType = "bomOverdue", extractor = BomDataExtractor.class)
    @PostMapping("/submit-ebom-approval/{bomId}/{days}")
    @Log(title = "提交BOM审批", businessType = BusinessType.UPDATE , nameField = "bomName")
    public R<BomMaster> submitEbomForApproval(@PathVariable Long bomId,
                                              @PathVariable Long days,
                                              @PathVariable(required = false) Long workflowInstanceId) {
        log.info("提交EBOM审批: bomId={}, workflowInstanceId={}", bomId, workflowInstanceId);
        try {
            BomMaster bomMaster = bomBusinessService.submitEbomForApproval(bomId,days,workflowInstanceId);
            return R.ok("BOM提交审批成功",bomMaster);
        } catch (Exception e) {
            log.error("提交BOM审批失败", e);
            return R.fail("BOM提交审批失败: " + e.getMessage());
        }
    }

    /**
     * 审批通过
     */
    @MonitorMethod(bizType = "bomOverdue", extractor = BomDataExtractor.class)
    @PostMapping("/approveBom/{bomId}")
    @Log(title = "BOM审批通过", businessType = BusinessType.UPDATE , nameField = "bomName")
    public R<BomMaster> approveBom(@PathVariable("bomId") Long bomId){
        log.info("BOM审批通过: bomId={}");
        try {
            BomMaster bomMaster = bomBusinessService.approveBom(bomId, LoginHelper.getUserId(), StatusEnum.YFB.getCode());
            return R.ok("BOM审批通过",bomMaster);
        } catch (Exception e) {
            log.error("提交BOM审批失败", e);
            return R.fail("提交BOM审批通过失败: " + e.getMessage());
        }
    }

    /**
     * 审批完成通过
     * bom完成审批时候调用
     */
    @PostMapping("/approveBomComplete/{bomId}")
    @Log(title = "BOM审批完成通过", businessType = BusinessType.UPDATE , nameField = "bomName")
    public R<BomMaster> approveBomComplete(@PathVariable("bomId") Long bomId){
        log.info("BOM审批通过: bomId={}");
        try {
            BomMaster bomMaster = bomBusinessService.approveBom(bomId, LoginHelper.getUserId(), StatusEnum.WC.getCode());
            return R.ok("BOM审批通过",bomMaster);
        } catch (Exception e) {
            log.error("提交BOM审批失败", e);
            return R.fail("提交BOM审批通过失败: " + e.getMessage());
        }
    }

    /**
     * 审批拒绝
     */
    @MonitorMethod(bizType = "bomOverdue", extractor = BomDataExtractor.class)
    @PostMapping("/rejectBom/{bomId}")
    public R<BomMaster> rejectBom(@PathVariable("bomId") Long bomId,String rejectReason){
        log.info("BOM审批拒绝: bomId={}");
        try {

            BomMaster bomMaster = bomBusinessService.rejectBom(bomId, rejectReason);
            return R.ok("BOM审批拒绝",bomMaster);
        } catch (Exception e) {
            log.error("提交BOM审批失败", e);
            return R.fail("提交BOM审批拒绝失败: " + e.getMessage());
        }
    }

    @MonitorMethod(bizType = "bomOverdue", extractor = BomDataExtractor.class)
    @PostMapping("/submitBomDays")
    @Log(title = "更新BOM任务时长", businessType = BusinessType.UPDATE, nameField = "bomName")
    public R<BomMaster> submitBomDays(@Valid @RequestBody BomCreationRequest request) {

        try {
            BomMaster result = bomBusinessService.submitBomDays(request);
            if (Objects.nonNull(request)) {
                return R.ok("更新时长成功",result);
            } else {
                return R.fail("更新时长失败");
            }
        } catch (Exception e) {
            log.error("创建设计BOM失败", e);
            return R.fail("创建设计BOM失败: " + e.getMessage());
        }
    }


    /**
     * 完成
     */
    @PostMapping("/completeBom")
    @Log(title = "完成BOM", businessType = BusinessType.UPDATE, nameField = "bomName")
    public R<BomMaster> completeBom(@Valid @RequestBody BomCreationRequest request) {

        try {
            BomMaster result = bomBusinessService.completeBom(request);
            if (Objects.nonNull(request)) {
                return R.ok("更新时长成功",result);
            } else {
                return R.fail("更新时长失败");
            }
        } catch (Exception e) {
            log.error("创建设计BOM失败", e);
            return R.fail("创建设计BOM失败: " + e.getMessage());
        }
    }

    /**
     * BOM转换 (EBOM -> PBOM -> MBOM)
     * @param request
     * @description 将设计BOM转换为工艺BOM或制造BOM
     * @return
     */
    @PostMapping("/convert-bom")
    @Log(title = "BOM转换", businessType = BusinessType.INSERT)
    public R<BomConversionResult> convertBom(@Valid @RequestBody BomConversionRequest request) {
        log.info("BOM转换请求: sourceBomId={}, targetBomType={}",
            request.getSourceBomId(), request.getTargetBomType());

        try {
            BomConversionResult result = bomBusinessService.convertEbomToMbom(request);
            if (Objects.nonNull(result)) {
                return R.ok("BOM转换成功",result);
            } else {
                return R.fail(result.getMessage());
            }
        } catch (Exception e) {
            log.error("BOM转换失败", e);
            return R.fail("BOM转换失败: " + e.getMessage());
        }
    }

    /**
     * 提交BOM变更请求
     * @param request
     * @return
     */
    @SaCheckPermission("bom:creation:edit")
    @PostMapping("/submit-change")
    @Log(title = "提交BOM变更", businessType = BusinessType.INSERT)
    public R<BomChangeResult> submitBomChange(@Valid @RequestBody BomChangeRequest request) {
        log.info("提交BOM变更请求: bomId={}, changeType={}", request.getBomId(), request.getChangeType());

        try {
            BomChangeResult result = bomBusinessService.submitBomChange(request);
            if (result.getSuccess()) {
                return R.ok( "BOM变更请求提交成功",result);
            } else {
                return R.fail(result.getMessage());
            }
        } catch (Exception e) {
            log.error("提交BOM变更失败", e);
            return R.fail("提交BOM变更失败: " + e.getMessage());
        }
    }

    /**
     * 实施BOM变更
     * @param changeLogId 变更记录ID
     * @description 执行已审批通过的BOM变更
     * @return
     */
    @PostMapping("/implement-change/{changeLogId}")
    @Log(title = "实施BOM变更", businessType = BusinessType.UPDATE)
    public R<Void> implementBomChange(@PathVariable Long changeLogId) {

        log.info("实施BOM变更: changeLogId={}", changeLogId);

        try {
            bomBusinessService.implementBomChange(changeLogId);
            return R.ok("BOM变更实施成功");
        } catch (Exception e) {
            log.error("实施BOM变更失败", e);
            return R.fail("实施BOM变更失败: " + e.getMessage());
        }
    }


    /**
     * 批量处理BOM变更
     * @param changeLogIds 变更记录ID列表
     * @param operatorId 操作人ID
     * @param operatorName 操作人姓名
     * @description 批量实施多个已审批的BOM变更
     * @return
     */
    @PostMapping("/batch-process-changes")
    @Log(title = "批量处理BOM变更", businessType = BusinessType.UPDATE)
    public R<Map<String, Object>> batchProcessBomChanges(@RequestBody List<Long> changeLogIds,
                                                         @RequestParam Long operatorId,
                                                         @RequestParam String operatorName) {

        log.info("批量处理BOM变更: changeLogIds={}, operatorId={}", changeLogIds, operatorId);

        try {
            Map<String, Object> result = bomBusinessService.batchProcessBomChanges(changeLogIds, operatorId, operatorName);
            return R.ok("批量处理完成",result);
        } catch (Exception e) {
            log.error("批量处理BOM变更失败", e);
            return R.fail("批量处理BOM变更失败: " + e.getMessage());
        }
    }


    /**
     * 生成MRP
     * 基于制造BOM生成物料需求计划
     * @param request
     * @return
     */
    @PostMapping("/generate-mrp")
    @Log(title = "生成MRP", businessType = BusinessType.OTHER)
    public R<MrpResult> generateMrp(@Valid @RequestBody MrpRequest request) {
        log.info("生成MRP请求: bomId={}, productionQuantity={}",
            request.getBomId(), request.getProductionQuantity());

        try {
            MrpResult result = bomBusinessService.generateMrp(request);

            if (result.getSuccess()) {
                return R.ok("MRP生成成功",result);
            } else {
                return R.fail(result.getMessage());
            }
        } catch (Exception e) {
            log.error("生成MRP失败", e);
            return R.fail("生成MRP失败: " + e.getMessage());
        }
    }


    /**
     * 生成增强版MRP
     * @param request
     * @description 生成包含需求合并和排序的增强版MRP
     * @return
     */
    @PostMapping("/generate-mrp-enhanced")
    @Log(title = "生成增强版MRP", businessType = BusinessType.OTHER)
    public R<MrpResult> generateMrpEnhanced(@Valid @RequestBody MrpRequest request) {
        log.info("生成增强版MRP请求: bomId={}, productionQuantity={}",
            request.getBomId(), request.getProductionQuantity());

        try {
            MrpResult result = bomBusinessService.generateMrpEnhanced(request);

            if (result.getSuccess()) {
                return R.ok("增强版MRP生成成功",result);
            } else {
                return R.fail(result.getMessage());
            }
        } catch (Exception e) {
            log.error("生成增强版MRP失败", e);
            return R.fail("生成增强版MRP失败: " + e.getMessage());
        }
    }

    /**
     * 获取BOM完整信息
     * @param bomId
     * @description = "获取BOM的完整信息，包括结构、版本历史、变更记录等"
     * @return
     */
    @GetMapping("/complete-info/{bomId}")
    public R<BomCompleteInfo> getBomCompleteInfo(@PathVariable Long bomId) {

        log.info("获取BOM完整信息: bomId={}", bomId);

        try {
            BomCompleteInfo info = bomBusinessService.getBomCompleteInfo(bomId);
            return R.ok("获取BOM完整信息成功",info);
        } catch (Exception e) {
            log.error("获取BOM完整信息失败", e);
            return R.fail("获取BOM完整信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取BOM变更影响分析
     * @param bomId
     * @param changeRequest
     * @description = "分析BOM变更对成本、供应链、生产的影响"
     * @return
     */
    @PostMapping("/change-impact-analysis/{bomId}")
    public R<Map<String, Object>> getBomChangeImpactAnalysis(@PathVariable Long bomId,
                                                             @Valid @RequestBody BomChangeRequest changeRequest) {

        log.info("BOM变更影响分析: bomId={}, changeType={}", bomId, changeRequest.getChangeType());

        try {
            Map<String, Object> analysis = bomBusinessService.getBomChangeImpactAnalysis(bomId, changeRequest);
            return R.ok("变更影响分析完成",analysis);
        } catch (Exception e) {
            log.error("BOM变更影响分析失败", e);
            return R.fail("BOM变更影响分析失败: " + e.getMessage());
        }
    }

    /**
     * 处理项目结束
     * @param projectId 项目ID
     * @param projectEndDate 项目结束日期
     * @return
     */
    @PostMapping("/handle-project-closing/{projectId}")
    @Log(title = "处理项目结束", businessType = BusinessType.UPDATE)
    public R<Void> handleProjectClosing(@PathVariable Long projectId, @RequestParam Date projectEndDate) {
        log.info("处理项目结束: projectId={}, endDate={}", projectId, projectEndDate);
        try {
            bomBusinessService.handleProjectClosing(projectId, projectEndDate);
            return R.ok("项目结束处理完成");
        } catch (Exception e) {
            log.error("处理项目结束失败", e);
            return R.fail("处理项目结束失败: " + e.getMessage());
        }
    }


    /**
     * 删除BOM信息
     * @param ids
     * @return
     */
    @SaCheckPermission("bom:creation:remove")
    @PostMapping("/delete/{ids}")
    @Log(title = "删除BOM信息", businessType = BusinessType.UPDATE)
    public R<Void> handleProjectClosing(@PathVariable List<Long> ids) {
        log.info("删除BOM信息: ids={}", ids);
        try {
            bomBusinessService.deleteBomByIds(ids);
            return R.ok("项目结束处理完成");
        } catch (Exception e) {
            log.error("处理项目结束失败", e);
            return R.fail("处理项目结束失败: " + e.getMessage());
        }
    }

    /**
     * 获取BOM类型说明
     * @return
     */
    @GetMapping("/bom-types")
    public R<Map<String, String>> getBomTypes() {
        Map<String, String> bomTypes = Map.of(
            "1", "设计BOM (EBOM) - 工程设计阶段的物料清单",
            "2", "工艺BOM (PBOM) - 考虑工艺要求的物料清单",
            "3", "制造BOM (MBOM) - 实际生产使用的物料清单"
        );
        return R.ok(bomTypes);
    }

    /**
     * 获取变更类型说明
     */
    @GetMapping("/change-types")
    public R<Map<String, String>> getChangeTypes() {
        Map<String, String> changeTypes = Map.of(
            "1", "新增 - 添加新的物料或结构",
            "2", "修改 - 修改现有物料或结构信息",
            "3", "删除 - 移除不需要的物料或结构",
            "4", "替换 - 用新物料替换现有物料"
        );
        return R.ok(changeTypes);
    }

    /**
     * 获取变更对象说明
     */
    @GetMapping("/change-objects")
    public R<Map<String, String>> getChangeObjects() {
        Map<String, String> changeObjects = Map.of(
            "1", "BOM基本信息 - BOM头部信息变更",
            "2", "BOM结构 - BOM结构树变更",
            "3", "物料信息 - 物料属性信息变更"
        );
        return R.ok(changeObjects);
    }

    /**
     * 验证BOM编码唯一性
     * @param bomCode
     * @param excludeId
     * @return
     */
    @GetMapping("/validate-bom-code")
    public R<Boolean> validateBomCode( @RequestParam String bomCode,
                                       @RequestParam(required = false) Long excludeId) {

        try {
            // 这里应该调用BomMasterService的验证方法
            //boolean exists = bomMasterService.isBomCodeExists(bomCode, excludeId);
            // return R.ok(!exists, exists ? "BOM编码已存在" : "BOM编码可用");
            return R.ok("BOM编码可用");
        } catch (Exception e) {
            log.error("验证BOM编码失败", e);
            return R.fail("验证BOM编码失败: " + e.getMessage());
        }
    }


    /**
     * 健康检查
     * @description = "检查BOM业务服务状态"
     * @return
     */
    @GetMapping("/health")
    public R<Map<String, Object>> healthCheck() {
        Map<String, Object> health = Map.of(
            "service", "BOM Business Service",
            "status", "UP",
            "timestamp", new Date(),
            "version", "1.0.0"
        );
        return R.ok(health);
    }


}
